using System;
using Microsoft.SPOT;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer;
using Gadgeteer.Interfaces;
using System.Collections;
using System.Threading;

namespace Dairy_Town
{
    class LocationManager
    {
        private bool synced = false;
        private GTM.Seeed.GPS gps;
        private GTM.Seeed.GPS.Position currentPos;
        private GT.Timer ValidityTimer; // Timer runs every two seconds to check interval since last position update

        // Latitude picked up by the device, defaults to 0.
        public double Latitude
        {
            get
            {
                return (currentPos == null) ? 0.0 : currentPos.Latitude;
            }
        }

        // Longitude picked up by the device, defaults to 0.
        public double Longitude
        {
            get
            {
                return (currentPos == null) ? 0.0 : currentPos.Longitude;
            }
        }

        // Heading picked up by the device, defaults to 0.
        public double Heading
        {
            get
            {
                return (currentPos == null) ? 0.0 : currentPos.CourseDegrees;
            }
        }

        // Timestamp picked up by the device, defaults to the default DateTime object created by the constructor.
        public DateTime Timestamp
        {
            get
            {
                return (currentPos == null) ? new DateTime() : currentPos.FixTimeUtc;
            }
        }

        /// <summary>
        /// LocationManager manages GPS module.
        /// </summary>
        /// <param name="instance">An instance of the GPS module</param>
        public LocationManager(GTM.Seeed.GPS instance)
        {
            this.gps = instance;

            this.gps.Enabled = true;
            this.gps.InvalidPositionReceived += gps_InvalidPositionReceived;
            this.gps.PositionReceived += gps_PositionReceived;

            // Timer which checks the age of the last valid position received by the device.
            ValidityTimer = new GT.Timer(13);
            ValidityTimer.Tick += (timer) =>
                {
                    if (currentPos == null)
                        return;
                    //Console.Display("GPS age is " + this.gps.LastValidPositionAge);
                    // If the last valid position was received over ten seconds ago, reset the GPS.
                    if (TimeSpan.Compare(this.gps.LastValidPositionAge, new TimeSpan(0,0,52)) == 1)
                        this.Reset();
                };
            ValidityTimer.Start();
            
            //Console.Display("GPS Enabled? " + gps.Enabled.ToString());
        }

        private bool timeout = false;

        /// <summary>
        /// Turns off the GPS module, waits half a second, and reinitializes all timers associated with the module.
        /// </summary>
        public void Reset()
        {
            return;

            if (timeout)
                return;

            ValidityTimer.Stop();
            //Console.Display("Reset GPS module");

            this.gps.Enabled = false;
            
            Thread.Sleep(500);
            
            this.gps.Enabled = true;
            this.gps.InvalidPositionReceived += gps_InvalidPositionReceived;
            this.gps.PositionReceived += gps_PositionReceived;
            this.timeout = true;

            //Console.Display("GPS Enabled? " + gps.Enabled.ToString());
            ValidityTimer.Start();
        }

        // Updates the currentPos variable with the newly received coordinate.
        void gps_PositionReceived(GTM.Seeed.GPS sender, GTM.Seeed.GPS.Position position)
        {
            this.timeout = false;

            if (this.gps.DebugPrintEnabled)
            {
                Debug.Print("Position: " + position + " (" + gps.LastValidPositionAge + ")");
            }

            if (!synced) // If local clock has not been set from GPS Satellite yet, then update local clock
            {
                synced = true;
                Microsoft.SPOT.Hardware.Utility.SetLocalTime(position.FixTimeUtc);
            }

            this.currentPos = position;
        }

        void gps_InvalidPositionReceived(GTM.Seeed.GPS sender)
        {
            Debug.Print("Invalid GPS Position");
        }
    }
}
